package com.hsh.learning.thread;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 2017/8/28.
 */
public class ThreadLocalDemo {

    //SimpleDateFormat缓存
    private static final Map<String, ThreadLocal<SimpleDateFormat>> sdfMap =
            new HashMap<String, ThreadLocal<SimpleDateFormat>>();
    //对象锁
    private static ReentrantLock sdfLock = new ReentrantLock();

    /**
     * @param pattern 格式规则
     * @return DateFormat
     * @Description: 推荐直接使用该方法 获取 DateFormat对象
     * 推荐理由：SimpleDateFormat非线程安全且生成开销大
     */
    public static SimpleDateFormat getDateFormat(final String pattern) {
        ThreadLocal<SimpleDateFormat> tl = sdfMap.get(pattern);
        if (tl == null) {
            try {
                //最多10毫秒
                if (!sdfLock.tryLock(10, TimeUnit.MILLISECONDS)) {
                    return new SimpleDateFormat(pattern);
                }
                tl = sdfMap.get(pattern);
                if (tl == null) {
                    tl = new ThreadLocal<SimpleDateFormat>() {
                        //这里重写initialValue，第一次get就获取该初始化，省去了set操作
                        @Override
                        protected SimpleDateFormat initialValue() {
                            return new SimpleDateFormat(pattern);
                        }
                    };
                    sdfMap.put(pattern, tl);
                }
            } catch (Exception exception) {

            } finally {
                sdfLock.unlock();
            }
        }
        return tl.get();
    }

    public static void main(String[] args) {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(1000, new Runnable() {
            @Override
            public void run() {
                System.out.println("1000个线程全部准备完毕");
            }
        });
        final CountDownLatch countDownLatch = new CountDownLatch(1000);
        final Random random = new Random();
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + "准备中");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                getDate(random);
                countDownLatch.countDown();
            }


        };
        for (int i = 0; i < 1000; i++) {
            new Thread(runnable).start();
        }
        try {
            countDownLatch.await();
            //System.gc();

            //每隔5s获取一次日期
            Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            getDate(random);
                            try {
                                TimeUnit.SECONDS.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                    System.out.println("get one object");
                }
            }, 5, 5, TimeUnit.SECONDS);

            //定时打印map信息
            Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    System.out.println(sdfMap);
                }
            }, 5, 5, TimeUnit.SECONDS);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true) {

        }
    }


    private static void getDate(Random random) {
        Date date = new Date(random.nextLong());
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String sourceDate = formatter.format(date);
        SimpleDateFormat simpleDateFormat = getDateFormat("yyyy-mm-dd HH:mm:ss");
        System.out.println(sdfMap);
        String format = simpleDateFormat.format(date);
        if (!sourceDate.equals(format)) {
            System.out.println(sourceDate.equals(format) + " source date : " + sourceDate + Thread.currentThread().getName() + ":" + format);
        }
    }


}
